#!/bin/bash

#====================================================================
# 运算符
# 原生bash不支持简单的数学运算
# 必须借助awk和expr命令来实现，expr最常用
# expr是一款表达式计算工具，使用它能完成表达式的求值操作。
# 参考：https://www.runoob.com/linux/linux-shell-basic-operators.html
#====================================================================

#--------------------------------------------
# 算术运算符
# + - \* / % = == != ++
#--------------------------------------------
# $(里面的变量需要写美元符)的用途 等价于`expr 表达式`
# $((里面的变量 美元符可写可不写))，*不需要转义，且运算符两边不用加空格
# []是test操作符的别名

echo '--------------算术运算符--------------'

a=100
b=400

result=$((100 + 200)) #写法1
echo "加运算100+200=$result"
# 注意两点：1、表达式和运算符之间要有空格，例如 100+200 是不对的，必须写成 100 + 200，这与我们熟悉的大多数编程语言不一样。
#         2、完整的表达式要被 ` ` 包含，注意这个字符不是常用的单引号，叫反引号，在 Esc 键下边。

result=`expr $a + $b` #写法2，推荐，个人感觉兼容性好
echo "加运算$a+$b=$result"

result=$((a + b)) #写法3，简洁，也推荐
echo "加运算$a+$b=$result"

result=$(expr $a + $b) #写法4
echo "加运算$a+$b=$result"

result=`expr $b - $a`
echo "减运算$b-$a=$result"

result=`expr $b \* $a` # 注意，*在shell中为通配符，作为运算符，需要转一下才能使用
echo "乘运算$b*$a=$result"

result=$(($a*$b)) #写法2，如果是$((表达式 美元符可写可不写))，*不需要转义，且运算符两边可以不加空格
echo "乘运算$a*$b=$result"

result=`expr $b / $a`
echo "除运算$b/$a=$result"

result=$((b / a))
echo "除运算$b/$a=$result"

result=`expr $b % $a`
echo "取余运算$b%$a=$result"

result=$((402 % a))
echo "取余运算402%$a=$result"

result=$(((a+b)*10/2)) 
echo "综合运算($a+$b)*10/2=$result"

result=$a
echo "赋值运算$result"

#补充
result=$((a + 100)) #但不适合\*，会报错
echo '不用expr的另一种写法，更简洁：$((a + 100))='$result

i=1
let "i++"
echo "i++的结果: $i"

#注意：条件表达式要放在方括号之间，并且要有空格，返回0假/1真
#比较数字时，用==和!=
if [ $a == $b ]; then
    echo "a==b"
fi

if [ $a != $b ]; then
    echo "a!=b"
fi

bool=$(expr $a == $b)
echo $bool

#--------------------------------------------
# 关系运算符
# -eq（equal）等于          -ne（not equal）不等于 
# -gt（greater than）大于   -ge（greater&equal）大于等于
# -lt（lower than）小于     -le（lower&equal）小于等于  
#--------------------------------------------

echo '--------------关系运算符--------------'
aa=100
bb=200
cc=200
dd=400

if [ $bb -eq $cc ]; then
    echo "$bb -eq $cc: bb等于cc"
else
    echo "$bb -eq $cc: bb不等于cc"
fi

if [ $aa -ne $bb ]; then
    echo "$aa -ne $bb: aa不等于bb"
else
    echo "$aa -ne $bb: aa等于bb"
fi

if [ $dd -gt $aa ]; then
    echo "$dd -gt $aa: dd大于aa"
else
    echo "$dd -gt $aa: dd不大于aa"
fi

if [ $dd -ge $aa ]; then
    echo "$dd -ge $aa: dd大于等于aa"
else
    echo "$dd -ge $aa: dd不大于等于aa"
fi

if [ $bb -lt $dd ]; then
    echo "$bb -lt $dd: bb小于dd"
else
    echo "$bb -lt $dd: bb不小于dd"
fi

if [ $bb -le $dd ]; then
    echo "$bb -le $dd: bb小于等于dd"
else
    echo "$bb -le $dd: bb不小于等于dd"
fi

#字符串比较
str="hello"
str2="hello "
str3="Hello"
str4="hello world"
str5="hello world"

if [ "$str" != "$str3" ]; then
    echo "$str和$str3是两个不同的字符串" #区分大小写
fi

if [ "$str" != "$str2" ]; then
    echo "$str和$str2是两个不同的字符串" #空格也参与比较
fi

if [ "$str4" == "$str5" ]; then
    echo "$str4和$str5是两个相同的字符串"
fi

#--------------------------------------------
# 布尔运算符
# !非运算  -o或运算  -a与运算
#--------------------------------------------

echo '--------------布尔运算符--------------'
aa=100
bb=200
if [ $a != $b ]; then
    echo "$aa != $bb : aa 不等于 bb"
else
    echo "$aa == $bb : a 等于 b"
fi

if [ $aa -lt 200 -a $bb -gt 100 ]; then
    echo "$aa小于200 且 $bb大于100 : 返回 1"
else
    echo "$aa小于200 且 $bb大于100 : 返回 0"
fi

if [ $aa -lt 100 -o $bb -gt 100 ]; then
    echo "$aa小于100 或 $bb大于100 : 返回 1"
else
    echo "$aa小于100 或 $bb大于100 : 返回 0"
fi

#--------------------------------------------
# 逻辑运算符
# &&（AND）  ||（OR）
#--------------------------------------------

aa=100
bb=200
echo '--------------逻辑运算符--------------'
if [[ $aa -lt 100 && $bb -gt 100 ]]; then #注意：这里是双中括号[[]]
    echo "$aa小于100 && $bb大于100 : 返回 1"
else
    echo "$aa小于100 && $bb大于 100 : 返回 0"
fi

if [[ $aa -lt 100 || $bb -gt 100 ]]; then
    echo "$aa小于100 || $bb大于100 : 返回 1"
else
    echo "$aa小于100 || $bb大于100 : 返回 0"
fi

#--------------------------------------------
# 文件测试运算符
# 注意：读写等权限依赖用户权限，当前用户不同，执行结果不同
#--------------------------------------------

echo '--------------文件测试运算符--------------'

file="/opt/shell-study/public/file/test.txt"
if [ -e $file ]; then    
    echo "${file}文件已存在，不再创建"
else
    touch $file
    if [ $? -eq 0 ]; then # -eq也可以用== 推荐用-eq，即关系运算符
        echo "创建$file完成"
      else
        echo "创建$file失败"
    fi
    echo "${file}文件不存在"
fi

#文件类型说明： -:普通文件，d:目录文件，b:块设备文件，c:字符设备文件，l:符号链，p:管道
if [ -f $file ]; then
    echo "${file}文件为普通文件，既不是目录，也不是设备文件"
else
    echo "${file}文件为特殊文件"
fi

dir="/opt/shell-study/"
if [ -d $dir ]; then #写法1
    echo "${dir}是目录"
else
    echo "${dir}不是目录"
fi

if test -d $dir; then #写法2 用test代替[]
    echo "${dir}是目录"
else
    echo "${dir}不是目录"
fi

#检测文件是否为可读
#切换到普通用户，/etc/shadow不是可读文件
file="/opt/shell-study/public/file/test.txt"
if [ -r $file ]; then
    echo "${file}文件可读"
else
    echo "${file}文件不可读"
fi

#检测文件是否为可写
# ??? 没有效果
file="/opt/shell-study/public/file/test.txt"
if [ -w $file ]; then
    echo "${file}文件可写"
else
    echo "${file}文件不可写"
fi

#检测文件是否为可执行
file="/opt/shell-study/public/file/test.txt"
if [ -x $file ]; then
    echo "${file}文件可执行"
else
    echo "${file}文件不可执行"
fi

#检测文件是否为空
file="/opt/shell-study/public/file/test.txt"
if [ -s $file ]; then
    echo "${file}文件不为空（文件大小>0）"
else
    echo "${file}文件为空（文件大小为0）"
fi

#检测文件（包括目录）是否存在
file="/opt/test123.txt"
if [ -e $file ]; then
    echo "${file}文件已存在"
else
    echo "${file}文件不存在"
fi

#检测文件是否设置了 SUID 位
file="/opt/shell-study/public/file/test.txt"
if [ -u $file ]; then
    echo "${file}文件设置了SUID位"
else
    echo "${file}文件没有设置SUID位"
fi

#检测文件是否设置了 SBID 位
file="/opt/shell-study/public/file/test.txt"
if [ -k $file ]; then
    echo "${file}文件设置了SBID位"
else
    echo "${file}文件没有设置SBID位"
fi

#检测文件是否存在并且是一个符号链接
file="/bin"
if [ -L $file ]; then
    echo "${file}是符号链接"
else
    echo "${file}不是符号链接"
fi

#检测文件是否为块设备文件
#可以先搜索socket类型文件 find / -type b
file="/dev/sda1"
if [ -b $file ]; then
    echo "${file}是块设备文件" #块设备，可以理解就是硬盘某个分区
else
    echo "${file}不是块设备文件"
fi

#检测文件是否为字符设备文件
file="/dev/null"
if [ -c $file ]; then
    echo "${file}是字符设备文件"
else
    echo "${file}不是字符设备文件"
fi

#检测文件是否为管道
file="/run/systemd/inhibit/1.ref"
if [ -p $file ]; then
    echo "${file}是管道文件"
else
    echo "${file}不是管道文件"
fi

#检测文件是否为socket文件
file="/var/lib/sss/pipes/nss"
if [ -S $file ]; then
    echo "${file}是socket文件"
else
    echo "${file}不是socket文件"
fi


